# -*- coding:utf-8 -*- #

from twisted.internet.protocol import Factory,Protocol,ClientCreator
from twisted.internet.reactor import callLater
from twisted.internet.task import LoopingCall
from twisted.internet import defer,threads

#使工作线程>512
import os
#if os.name!='nt':
    #from twisted.internet import epollreactor
    #epollreactor.install()    
#else:
    #from twisted.internet import iocpreactor
    #iocpreactor.install()
    
from twisted.internet import reactor
from twisted.python import log
from twisted.python.logfile import DailyLogFile

from twisted.protocols import basic
from twisted.protocols.basic import LineReceiver
from twisted.web import resource,static,server

from twisted.protocols import ftp
from twisted.cred import portal,checkers
from zope.interface import implements
from twisted.python import filepath

from twisted.internet.error import CannotListenError


from mconfig import MServerConfig
import data_analysis
import sys
import time
from factorywork import workRegos,workLostClient
#from monitorcron import watchfile

class MServer(LineReceiver):
    def __init__(self):
        self.recvBuf = ""
        self.clientinfo = {} # 信息格式 {'000c29b3972f': '192.168.168.100'}

        self.uid = None     #用来存储server_sn
        self.threads = []    #单用户的并发线程池
        
    #发送文本格式数据
    def sendData(self,callid,data):
        newdata = data_analysis.sendData(callid,data)
        self.transport.write(newdata)
    
    def sendError(self,callid,act,msg,disconn=False,pdata=None):
        errmsg = {}
        errmsg['succ']=0
        errmsg['act']=act
        errmsg['msg']= msg
        errmsg['data']= pdata
        self.sendData(callid,errmsg)
        #主动断开客户端连接
        if disconn:
            self.transport.loseConnection()
            

    #连接断开时候发生
    def connectionLost(self, reason):
        #客户端端口后调用 ＃主动踢掉client通过sendError进行
        #print("OutUser : %s"%(self.transport.getPeer()))
        self.removeFactoryClientips()
        Protocol.connectionLost(self, reason)
        
        if self.uid != None:
            self.factory.delClient(self)
        
    #新客户端进入
    def connectionMade(self):
        #连接客户端的ip地址
        selfip = self.transport.getPeer().host
        
        print "self.transport===>",type(self.transport.getPeer())
        
        if MServerConfig['DEBUG'] !=0 :
            
            print("NewClient---> : %s"%(selfip))
        if selfip in MServerConfig['refuseIpList'] :
            #不允许连接的ip
            self.sendError(0,'login','Same Ip is connected',True)
        elif selfip in self.factory.clientips :
            #只允许单一实例连接
            self.sendError(0,'login','Same Ip is connect',True)   
        else:
            self.factory.clientips.append(selfip)

            #记录客户端标识 格式 {'192.168.168.100': <__main__.MServer instance at 0x3010d40>}
            #AllClients[selfip] = self
            
            #callLater(MServerConfig['checkAfterConnect'],self.checkislogin)
            print("NewUser : %s"%(self.transport.getPeer()))
        
    #def checkislogin(self):
        #self.removeFactoryClientips()
        #if (self.uid==0 or self.uid==None) and self.adminlevel==0 :
            #self.sendError(0,'login','First Need Login',True)

    def removeFactoryClientips(self):
        selfip = self.transport.getPeer().host
        print "selfip lost=====>",selfip
        if selfip in self.factory.clientips :
            self.factory.clientips.remove(selfip)

    #接收数据
    def dataReceived(self, data):
        self.recvBuf += data
        cmddata = None
        while len(self.recvBuf):
            try:
                getdecode = data_analysis.decodedata(self.recvBuf,data)
                print "getdecode--->",getdecode
                if getdecode is True:
                    break
                if getdecode is False:
                    self.recvBuf=""
                    break
                self.recvBuf = getdecode[0]
                callid = getdecode[1]
                cmddata = getdecode[2]
            except:
                log.err()
#                print('except in decompress or jsonDecode !')
#                print( repr(getdecode) )
                self.sendError(0,'except','except in dataReceived',True)
            if cmddata is not None:
                self.exeRecvData(cmddata,callid)

    def exeRecvData(self,cmddata,callid):
        try:
            if not cmddata.has_key('act'):
                self.sendError(callid,'undefined','undefined action',True)
            else:
                self.InvokeAction(callid,cmddata)
        except:
            log.err()
            
    #命令调度控制
    def InvokeAction(self,callid,cmddata):
        act = cmddata.pop('act')
        if act == 'regos':
            #注册主机，并写入数据库
            workRegos(cmddata)
            
            server_sn = cmddata['server_sn']
            self.uid = server_sn
            self.factory.addClient(self,cmddata)

        elif act == 'end':
            #ep返回执行脚本结果
            workEnd(cmddata)
        else:
            print "Not Found act"
    
class MServerFactory(Factory):
    protocol = MServer
    #本系统最大允许10000人同时在线
    max_connections = 10000
    timeout = 3
    perdefer = 4 #每个进程运行的子线程数
    
    def __init__(self):
        self.clientips = [] # [ipaddr]   {ipaddr:nums}
        self.clients = {}   #{uid:<self>}
        self.servers = {} #存储到并行服务器的连接
        self.delayCallInstance = {}

    def addCallInstance(self,callid,calltype,instance,params):
        callid = str(callid)
        if not self.delayCallInstance.has_key(callid):
            self.delayCallInstance[callid] = [calltype,instance,params]
            
    def removeCallInstance(self,callid):
        callid = str(callid)
        ret = 0
        if self.delayCallInstance.has_key(callid):
            if  self.delayCallInstance[callid][1]!=None :
                if self.delayCallInstance[callid][0] == 'callLater' and self.delayCallInstance[callid][1].called==0:
                    self.delayCallInstance[callid][1].cancel()
                elif self.delayCallInstance[callid][0] == 'LoopingCall':
                    self.delayCallInstance[callid][1].stop()
                ret = callid
                self.delayCallInstance[callid][1]=None
            del self.delayCallInstance[callid]
        return ret

    def addClient(self,client,clientdata={}):
        if client.uid == None:
            client.sendError(0,'login','No UserId',True)
            return False
        else:
            oldclient = None
            uidkey = str(client.uid)
            if self.clients.has_key(uidkey):
                oldclient = self.clients[uidkey]
                oldclient.sendError(0,'Otherlogin','Other Client Logined',True)
                self.delClient(oldclient)

            self.clients[uidkey]=client
            print "self.clients===>",self.clients
            if clientdata.has_key('conninfo'):
                ret = clientdata['conninfo']
                ret['starttime'] = time.time()
            else:
                ret = {'starttime':time.time()}
            return ret

    def delClient(self, client):
        if client.uid != None:
            uidkey = str(client.uid)
            if self.clients.has_key(uidkey) and self.clients[uidkey]==client:
                del self.clients[uidkey]

        client.transport.loseConnection()
        print '==>loseConnection:delClient',client.uid
        #修改数据库注册机器的状态
        workLostClient(client.uid)

        
    def set_protocol(self,p,sidkey,sclient,msg=None):
        print '=========MServerFactory========set_protocol'
        p.sclient = sclient
        p.sid = sidkey
        p.sfactory = self
        self.servers[sidkey] = p
        logindata = {'act':'admin','callid':1 ,'uid':MServerConfig['SERVE_INDEX'],'conninfo':{'adminrole':{}}}
        self.servers[sidkey].sendData(0,logindata)
        if msg is not None:
            self.servers[sidkey].sendData(0,msg)
            
    def end_protocol(self,p,sidkey):
        print '=========MServerFactory========end_protocol'
        print p
        if self.servers.has_key(sidkey):
            del self.servers[sidkey]

            
class MServerFTPRealm:
    implements(portal.IRealm)

    def __init__(self, anonymousRoot):
        self.anonymousRoot = filepath.FilePath(anonymousRoot)
        self.dir = MServerConfig['FTP_USER_DIR']

    def requestAvatar(self, avatarId, mind, *interfaces):
        for iface in interfaces:
            if iface is ftp.IFTPShell:
                if avatarId is checkers.ANONYMOUS:
                    avatar = ftp.FTPAnonymousShell(self.anonymousRoot)
                else:
                    user_dir = self.dir[avatarId]
                    avatar = ftp.FTPShell(filepath.FilePath(user_dir))
                return ftp.IFTPShell, avatar, \
                       getattr(avatar, 'logout', lambda: None)
        raise NotImplementedError(\
            "Only IFTPShell interface is supported by this realm")

if __name__ == '__main__':

    #得到程序运行目录
    root_dir = os.path.abspath(os.path.dirname(__file__))

    ##将打印都输出到文件中
    #if MServerConfig['CMLOG']!='' :
        #log.startLogging(DailyLogFile.fromFullPath(MServerConfig['CMLOG']))
        
    try:
        reactor.listenTCP(MServerConfig['SERVE_PORT'], MServerFactory())
        reactor.suggestThreadPoolSize(MServerConfig['suggestThreadPoolSize'])
        print "\033[32;1mRunning Socket on %s:%s\033[0m" % ("", str(MServerConfig['SERVE_PORT']))
    except CannotListenError:
        print "\033[31;1mSocket %s  Address already in use.\033[0m" % str(MServerConfig['SERVE_PORT'])
        sys.exit()
    
#    d=threads.deferToThread(aSillyBlockingMethod,"2 secodns have passed")
#    d.addCallback(printResult)


    #执行计划任务
    #reactor.callInThread(watchfile,root_dir)
 
    reactor.run()
    